﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using FA.Library.Plugin;
using FA.Library.Util;
using NLog;
using System.Collections.ObjectModel;
using System.IO;
using FA.FlightAttendant.Properties;
using System.Xml;
using FA.FlightAttendant.Plugin;
using System.Windows;
using FA.Library.Sim;

namespace FA.FlightAttendant.Host
{
    public class SimHost
    {
        private static readonly Logger _logger = LogManager.GetCurrentClassLogger();

        #region Singleton

        /// <summary>
        /// Singleton instance.
        /// </summary>
        public static SimHost Instance
        {
            get { return _instance; }
        }
        private static readonly SimHost _instance = new SimHost();

        #endregion

        /// <summary>
        /// The currently loaded simulators.
        /// </summary>
        public ObservableCollection<Simulator> Simulators
        {
            get
            {
                return _simulators;
            }
        }
        private ObservableCollection<Simulator> _simulators;

        /// <summary>
        /// The state manager for the simulator plugins.
        /// </summary>
        private SimStateManager _simStateManager;

        /// <summary>
        /// Private constructor.
        /// </summary>
        private SimHost()
        {
            _simulators = new ObservableCollection<Simulator>();
            _simStateManager = new SimStateManager(_simulators);
        }

        /// <summary>
        /// Unregister all simulators and dispose this host.
        /// </summary>
        public void Dispose()
        {
            while (_simulators.Count > 0)
            {
                UnregisterSimulator(_simulators[0], true);
            }
        }
        
        #region Sim Management

        /// <summary>
        /// Load the simulators from the XML file.
        /// </summary>
        public void LoadSimulators()
        {
            // Read the simulator XML file to create the sims
            string simulatorFile = Path.Combine(Environment.CurrentDirectory, Settings.Default.SimulatorsFile);
            SimulatorFileReader reader = new SimulatorFileReader(simulatorFile);
            List<Simulator> simulators = reader.CreateSimulators();

            // Register the simulators
            foreach (Simulator sim in simulators)
                RegisterSimulator(sim);
        }

        /// <summary>
        /// Register a simulator to be managed by this host.
        /// </summary>
        /// <param name="sim"></param>
        public void RegisterSimulator(Simulator sim)
        {
            // Initialise the simulator
            sim.Initialise();

            // Register the state manager for sim events
            _simStateManager.RegisterSimulatorEvents(sim);

            // Unregister simulator on disposal
            sim.Disposed += (s, e) =>
            {
                if (s is Simulator)
                    UnregisterSimulator(s as Simulator, false);
            };

            // Add the sim to the list
            _simulators.Add(sim);
            _logger.Info("Registered simulator '" + sim.Name + "'.");
        }

        /// <summary>
        /// Unregister the simulator with the given name.
        /// </summary>
        /// <param name="simName"></param>
        /// <param name="disposeSimulator"></param>
        public void UnregisterSimulator(string simName, bool disposeSimulator)
        {
            Simulator sim = null;

            foreach (Simulator currentSim in _simulators)
            {
                if (currentSim.Name.Equals(simName))
                {
                    sim = currentSim;
                    break;
                }
            }

            if (sim != null)
            {
                UnregisterSimulator(sim, disposeSimulator);
            }
        }

        /// <summary>
        /// Unregister a simulator from this host.
        /// </summary>
        /// <param name="sim"></param>
        /// <param name="dispose"></param>s
        public void UnregisterSimulator(Simulator sim, bool disposeSimulator)
        {
            _simulators.Remove(sim);
            if (disposeSimulator && !sim.IsDisposed)
                sim.Dispose();
        }

        /// <summary>
        /// Check if the given simulator is being managed by this host.
        /// </summary>
        /// <param name="simName"></param>
        /// <returns></returns>
        public bool ManagesSimulator(string simName)
        {
            bool managesSim = false;

            foreach (Simulator currentSim in _simulators)
            {
                if (currentSim.Name.Equals(simName))
                {
                    managesSim = true;
                    break;
                }
            }

            return managesSim;
        }

        /// <summary>
        /// Check if the given simulator is being managed by this host.
        /// </summary>
        /// <param name="sim"></param>
        /// <returns></returns>
        public bool ManagesSimulator(Simulator sim)
        {
            return _simulators.Contains(sim);
        }

        #endregion

        public void StartSimulator(Simulator sim)
        {
            try
            {
                sim.Start();
            }
            catch (Exception ex)
            {
                _logger.ErrorException("Unable to run simulator '" + sim.Name + "'.", ex);
                MessageBox.Show(
                    "Unable to run simulator '" + sim.Name + "'.\n\n" + ex.Message,
                    sim.Name,
                    MessageBoxButton.OK,
                    MessageBoxImage.Warning);
            }
        }

        public void StopSimulator(Simulator sim)
        {
            try
            {
                sim.Stop();
            }
            catch (Exception ex)
            {
                _logger.ErrorException("Unable to stop simulator '" + sim.Name + "'.", ex);
                MessageBox.Show("Unable to stop simulator '" + sim.Name + "'.\n\n" + ex.Message, sim.Name, MessageBoxButton.OK, MessageBoxImage.Warning);
            }
        }
    }
}